package com.doctcloud.common.core.algorithm;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 异常检测工具类，基于正态分布原理检测数据是否异常
 * 支持 Integer 和 Double 类型，通过泛型实现通用化
 */
public class DetectAnomaly {

    /**
     * 检测结果常量
     */
    public static final int NO_DATA = 0;         // 无数据
    public static final int NORMAL = 1;          // 正常
    public static final int INSUFFICIENT_DATA = 2; // 数据不足
    public static final int TOO_LOW_ANOMALY = 3;  // 过低异常
    public static final int TOO_HIGH_ANOMALY = 4; // 过高异常

    /**
     * 基于正态分布检测异常值（泛型版本）
     * @param dataList 待检测的数据列表
     * @param k 标准差倍数（建议2-3，值越大正常范围越宽）
     * @return 检测结果码（对应常量）
     */
    public static <T extends Number> int detectAnomaly(List<T> dataList, int k) {
        // 1. 空值校验
        if (dataList == null || dataList.isEmpty()) {
            return NO_DATA;
        }

        // 2. 过滤无效数据并校验数据量
        List<Double> validData = dataList.stream()
                .map(Number::doubleValue)  // 统一转换为Double
                .filter(amount -> amount != null)  // 过滤null值（理论上Number类型不会为null，但保留防御性校验）
                .collect(Collectors.toList());

        if (validData.size() < 10) {
            return INSUFFICIENT_DATA;
        }

        // 3. 计算统计量（均值和标准差）
        double mean = calculateMean(validData);
        double stdDev = calculateStdDev(validData, mean);

        // 处理标准差为0的特殊情况（所有数据相同）
        if (stdDev == 0) {
            return NORMAL;
        }

        // 4. 定义正常范围
        double lowerBound = mean - k * stdDev;
        double upperBound = mean + k * stdDev;

        // 5. 检测异常值
        for (double value : validData) {
            if (value < lowerBound) {
                return TOO_LOW_ANOMALY;
            } else if (value > upperBound) {
                return TOO_HIGH_ANOMALY;
            }
        }

        // 6. 无异常情况
        return NORMAL;
    }

    /**
     * 计算均值（μ）
     */
    private static double calculateMean(List<Double> data) {
        return data.stream()
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0.0);
    }

    /**
     * 计算样本标准差（σ）
     * 公式：√[Σ(xi-μ)²/(n-1)]
     */
    private static double calculateStdDev(List<Double> data, double mean) {
        if (data.size() <= 1) {
            return 0.0;
        }

        double sumOfSquares = data.stream()
                .mapToDouble(val -> Math.pow(val - mean, 2))
                .sum();

        return Math.sqrt(sumOfSquares / (data.size() - 1));
    }

    /**
     * 便捷方法（使用默认k=2）
     */
    public static <T extends Number> int detectAnomaly(List<T> dataList) {
        return detectAnomaly(dataList, 2);
    }

    /**
     * 支持自定义数值提取的泛型方法（适用于实体类）
     * @param dataList 实体类数据列表
     * @param valueExtractor 数值提取函数
     * @param k 标准差倍数
     * @param <T> 实体类型
     * @return 检测结果码
     */
    public static <T> int detectAnomaly(List<T> dataList,
                                        Function<T, ? extends Number> valueExtractor,
                                        int k) {
        if (dataList == null || dataList.isEmpty()) {
            return NO_DATA;
        }

        List<Double> validData = dataList.stream()
                .map(valueExtractor)
                .map(Number::doubleValue)
                .filter(amount -> amount != null)
                .collect(Collectors.toList());

        if (validData.size() < 10) {
            return INSUFFICIENT_DATA;
        }

        return detectAnomaly(validData, k);
    }

    /**
     * 便捷方法：自定义数值提取 + 默认k=2
     */
    public static <T> int detectAnomaly(List<T> dataList, Function<T, ? extends Number> valueExtractor) {
        return detectAnomaly(dataList, valueExtractor, 2);
    }
}